package com.twittex.model
{
	import com.adobe.serialization.json.JSON;
	import com.arc90.rpc.events.FaultEvent;
	import com.arc90.rpc.events.ResultEvent;
	import com.arc90.rpc.rest.RESTService;
	import com.arc90.rpc.rest.RESTServiceMethod;
	import com.twittex.TwittexFacade;
	import com.twittex.model.helpers.URLEncoding;
	import com.twittex.model.helpers.URLParser;
	
	import flash.utils.ByteArray;
	
	import mx.utils.URLUtil;
	
	import org.puremvc.as3.patterns.proxy.Proxy;

	public class StatusProxy extends Proxy
	{
		public static const NAME:String = "StatusProxy";

		private static const TWITTER_FRIENDS_FEED:String = "https://twitter.com/statuses/friends_timeline.json";
		private static const TWITTER_STATUS_UPDATE:String = "https://twitter.com/statuses/update.json?status=";
		private static const TWITTER_REPLIES_FEED:String = "https://twitter.com/statuses/replies.json";
		
		private static const TWITPIC_UPLOAD:String = "http://twitpic.com/api/upload";
		private static const TWITPIC_RESPONSE_OK:String = "ok";
		private static const TWITPIC_RESPONSE_FAIL:String = "fail";
		
		private static const TINYURL_CREATE:String = "http://tinyurl.com/api-create.php?url=";
		
		private static const MIN_URL_LENGTH:uint = 25;
		
		private var loginProxy:LoginProxy;


		public function StatusProxy(proxyName:String=null, data:Object=null)
		{
			super(NAME, data);

			loginProxy = facade.retrieveProxy(LoginProxy.NAME) as LoginProxy;
		}
		
		public function findFriendsStatuses():void {
			var service:RESTService = new RESTService();
			service.setCredentials(loginProxy.getData().login, loginProxy.getData().password);
			service.url = TWITTER_FRIENDS_FEED;
			service.method = RESTServiceMethod.GET;
			service.resultFormat = RESTService.RESULT_FORMAT_TEXT;
				
			var successHandler:Function = function (event:ResultEvent):void {
				var rawData:String = String(event.result);
				var statuses:Array = JSON.decode(rawData) as Array;

				sendNotification(TwittexFacade.FRIEND_STATUSES_FOUND, statuses.map(parseStatuses));
			}
			
			var failHandler:Function = function (event:FaultEvent):void {

			}

			service.addEventListener(ResultEvent.RESULT, successHandler);
			service.addEventListener(FaultEvent.FAULT, failHandler);
			service.send();
		}
		
		public function updateStatus(message:String):void {
			var onStatusShorted:Function = function (shortedMessage:String):void {
				var service:RESTService = new RESTService();
				service.setCredentials(loginProxy.getData().login, loginProxy.getData().password);
				service.url = TWITTER_STATUS_UPDATE + URLEncoding.encode(shortedMessage);
				service.method = RESTServiceMethod.POST;
				service.resultFormat = RESTService.RESULT_FORMAT_TEXT;
					
				var successHandler:Function = function (event:ResultEvent):void {
					var rawData:String = String(event.result);
					var status:Object = JSON.decode(rawData);
	
					//setData(tryLogin);
					//TODO: Parse each entry text
					sendNotification(TwittexFacade.STATUS_UPDATED, status);
				}
				
				var failHandler:Function = function (event:FaultEvent):void {
	
				}
	
				service.addEventListener(ResultEvent.RESULT, successHandler);
				service.addEventListener(FaultEvent.FAULT, failHandler);
				service.send();
			}
			
			shortStatus(message, onStatusShorted);
		}

		public function findRepliesStatuses():void {
			var service:RESTService = new RESTService();
			service.setCredentials(loginProxy.getData().login, loginProxy.getData().password);
			service.url = TWITTER_REPLIES_FEED;
			service.method = RESTServiceMethod.GET;
			service.resultFormat = RESTService.RESULT_FORMAT_TEXT;
				
			var successHandler:Function = function (event:ResultEvent):void {
				var rawData:String = String(event.result);
				var statuses:Array = JSON.decode(rawData) as Array;

				//setData(tryLogin);
				//TODO: Parse each entry text
				sendNotification(TwittexFacade.REPLIES_STATUSES_FOUND, statuses);
			}
			
			var failHandler:Function = function (event:FaultEvent):void {

			}

			service.addEventListener(ResultEvent.RESULT, successHandler);
			service.addEventListener(FaultEvent.FAULT, failHandler);
			service.send();
		}
		
		public function uploadImage(name:String, data:ByteArray):void {
			var service:RESTService = new RESTService();
			var request:Object = {'username':loginProxy.getData().login,
								  'password':loginProxy.getData().password,
								  'media':{'filename':name,'mimetype':'image/png','data':data}};

			service.url = TWITPIC_UPLOAD;
			service.method = RESTServiceMethod.POST;
			service.contentType = RESTService.CONTENT_TYPE_MULTIPART;
			service.request = request;
			service.showBusyCursor = true;
			
			var successHandler:Function = function (event:ResultEvent):void {
				var result:XML = event.result as XML;
				var status:String = result.attribute('stat');

				if(status.toLowerCase() == TWITPIC_RESPONSE_OK) {
					var url:String = result.mediaurl;
					sendNotification(TwittexFacade.IMAGE_UPLOADED, url);
				} else if(status.toLowerCase() == TWITPIC_RESPONSE_FAIL) {
					var error:String = result.err.attribute('msg');
					sendNotification(TwittexFacade.IMAGE_FAILED, error);
				}
			}

			service.addEventListener(ResultEvent.RESULT, successHandler);
			service.send();
		}
		
		/**
		 * Shorts status message using TinyURL service to make smaller url's
		 */ 
		private function shortStatus(message:String, callback:Function):void {
			var service:RESTService = new RESTService();
			service.method = RESTServiceMethod.POST;
			service.resultFormat = RESTService.RESULT_FORMAT_TEXT;
			service.request = "<body/>"; // dummy request (avoid 411 error)

			var tokens:Array = message.split(/\s+/);
			var links:Array = new Array();
			// find url's in status message
			for each(var token:String in tokens)
				if(URLUtil.isHttpURL(token) && token.length > MIN_URL_LENGTH)
					links.push(token);

			var onLinkCreated:Function = function (event:ResultEvent):void {
				// replace received link in tokens array
				var index:int = tokens.indexOf(links.pop() as String);
				tokens[index] = event.result as String;
				
				// request next link
				if(links.length > 0) {
					service.url = TINYURL_CREATE + links[0];
					service.send();
				// finished, invoke callback function
				} else {
					callback.call(this, tokens.join(" "));
				}
			}
			
			var onLinkFault:Function = function (event:FaultEvent):void {
				links.pop(); // This link couldn't be shorten
				// request next link
				if(links.length > 0) {
					service.url = TINYURL_CREATE + links[0];
					service.send();
				// finished, invoke callback function
				} else {
					callback.call(this, tokens.join(" "));
				}
			}
			
			// request first link
			if(links.length > 0) {
				service.url = TINYURL_CREATE + links[0];
				service.addEventListener(ResultEvent.RESULT, onLinkCreated);
				service.addEventListener(FaultEvent.FAULT, onLinkFault);
				service.send();
			// no url's found
			} else {
				callback.call(this, message);
			}
		}
		
		private function parseStatuses(status:*, index:int, statuses:Array):Object {
			status.text = URLParser.urlToATag(status.text as String);
			return status;
		}

	}
}